package cn.jhz.learn.community_dynamic.manager;

import cn.jhz.learn.community_dynamic.common.util.UniversalUtil;
import cn.jhz.learn.community_dynamic.dao.RoleJpaRepository;
import cn.jhz.learn.community_dynamic.dao.UserJpaRepository;
import cn.jhz.learn.community_dynamic.model.AclEntity;
import cn.jhz.learn.community_dynamic.model.RoleEntity;
import cn.jhz.learn.community_dynamic.model.UserEntity;
import cn.jhz.learn.community_dynamic.security.manager.SecurityUserManager;
import cn.jhz.learn.community_dynamic.security.model.SimpleGrantedResource;
import cn.jhz.learn.community_dynamic.security.model.SimpleGrantedRole;
import cn.jhz.learn.community_dynamic.security.model.SimpleGrantedUser;
import cn.jhz.learn.community_dynamic.vo.wbms.ColumnType;
import cn.jhz.learn.community_dynamic.vo.wbms.UserView;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

@Service
public class UserManager extends SecurityUserManager<UserEntity> {
    private final UserJpaRepository userRepository;
    private final PasswordEncoder passwordEncoder;
    private final RoleJpaRepository roleJpaRepository;
    private final LoginIdManager loginIdManager;

    @Autowired
    public UserManager(UserJpaRepository userRepository, RoleJpaRepository roleJpaRepository,
	    LoginIdManager loginIdManager) {
	this.userRepository = userRepository;
	this.passwordEncoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
	this.roleJpaRepository = roleJpaRepository;
	this.loginIdManager = loginIdManager;
    }

    public UserEntity newInstanceByPhone(String phone) {
	// TODO 添加默认用户角色
	// TODO 添加用户信息默认值
	// TODO 添加用户基本信息默认值
	return UserEntity.builder().phone(phone).username("手机用户_" + UniversalUtil.generateString(5))
		.loginId(loginIdManager.getEntity().getId()).password(passwordEncoder.encode("123456"))
		.registrationTime(new Date()).status((byte) 1).userBinds(new HashSet<>()).build();
    }

    public UserEntity newInstanceByUser(UserView user) {
	return UserEntity.builder()
		.password(passwordEncoder.encode(user.getPassword() == null ? "123456" : user.getPassword()))
		.username(user.getUsername()).email(user.getEmail()).phone(user.getMobile())
		.loginId(loginIdManager.getEntity().getId()).registrationTime(new Date()).status((byte) 1)
		.userBinds(new HashSet<>()).roles(new HashSet<>(roleJpaRepository.findAllById(user.getRoleIds())))
		.build();
    }

    public Optional<UserEntity> getUserDetailByPhone(String phone) {
	return this.userRepository.findByPhone(phone);
    }

    public Optional<UserEntity> getUserDetailByEmail(String email) {
	return this.userRepository.findByEmail(email);
    }

    /**
     * TODO 第三方绑定
     * 
     * @param openId
     * @param provider
     * @return
     */
    public Optional<UserEntity> getUserDetailByOtherBind(String openId, String provider) {
	return Optional.empty();
    }

    public Optional<UserEntity> getUserDetailByLoginId(String loginId) {
	return this.userRepository.findByLoginId(Long.valueOf(loginId));
    }

    @Override
    public Optional<UserEntity> getUserDetailByUsername(String username) {
	return this.userRepository.findByUsername(username);
    }

    @Override
    @Transactional
    public void createUserByPhone(String phone) {
	userRepository.save(this.newInstanceByPhone(phone));
    }

    @Transactional
    public UserEntity addInstance(UserEntity user) {
	/* 插入用户&信息 */
	return this.userRepository.save(user);
    }
    
    @Transactional
    public void deleteBlack(UserEntity entity, UserEntity blackEntity) {
	entity.removeBlack(blackEntity);
	this.userRepository.saveAndFlush(entity);
    }
    
    @Transactional
    public void deleteFollow(UserEntity entity, UserEntity followEntity) {
	entity.removeFollow(followEntity);
	this.userRepository.saveAndFlush(entity);
    }
    
    @Transactional
    public UserEntity updateInstanceColumn(UserEntity entity, ColumnType columnType, Object value) {
	switch (columnType) {
	    case EMAIL:
		// 校验是否存在相同
		this.userRepository.setFixedEmailFor((String) value,entity);
		break;
	    case MOBILE:
		this.userRepository.setFixedPhoneFor((String) value,entity);
		break;
	    case USERNAME:
		this.userRepository.setFixedUsernameFor((String) value,entity);
		break;
	    case PASSWORD:
		this.userRepository.setFixedPasswordFor((String) value,entity);
		break;
	    case USERPIC:
		this.userRepository.setFixedUserpicFor((String) value,entity);
		break;
	    case ROLES:
		Set<RoleEntity> roles = new HashSet<>();
		@SuppressWarnings("unchecked") List<Integer> ids = new ArrayList<>((Set<Integer>)value);
		Set<Integer> newRoles = new HashSet<>();
		// 过滤出不存在的role
		// 将新的role插入
		entity.getRoles().stream().filter(role -> ids.contains(role.getId())).forEach(roles::add);
		List<Integer> temp = roles.stream().map(RoleEntity::getId).collect(Collectors.toList());
		ids.stream().filter(id -> !temp.contains(id)).forEach(newRoles::add);

		if (newRoles.size() < 1) {
		    if (entity.getRoles().size() == roles.size()) {
			return entity;
		    }
		}
		roles.addAll(roleJpaRepository.findAllById(newRoles));
		entity.setRoles(roles);
		break;
	    case STATUS:
		entity.setStatus((Byte) value);
		break;
	    default:
		break;
	    }

	return entity;
    }

    @Override
    public UserDetails adpt(SimpleGrantedUser obj) {
	UserEntity user = (UserEntity) obj;
	List<GrantedAuthority> grantedAuthorities = new ArrayList<>();

	user.getRoles().forEach(role -> {
	    grantedAuthorities.add(new SimpleGrantedRole(role.getName()));
	    grantedAuthorities.addAll(role.getAcls().stream().map(AclEntity::getName).map(SimpleGrantedResource::new)
		    .collect(Collectors.toList()));
	});

	return User.builder().username(String.valueOf(user.getLoginId())).password(user.getPassword())
		.disabled(user.getStatus() != (byte) 1).authorities(grantedAuthorities).build();
    }

}

//public Long countByRoleId(Integer roleId) {
//	Specification<UserEntity> specification = new Specification<UserEntity>() {
//	    /**
//	     * 
//	     */
//	    private static final long serialVersionUID = 8403620637479648477L;
//
//	    @Override
//	    public Predicate toPredicate(Root<UserEntity> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
//		List<Predicate> predicates = new ArrayList<>();
//		//根据roleId 查询 user
//		Join<RoleEntity, UserEntity> join = root.join("roles", JoinType.LEFT);
//		predicates.add(criteriaBuilder.equal(join.get("id"), roleId));
//		
//		return query.where(predicates.toArray(new Predicate[predicates.size()])).getRestriction();
//	    }
//	};
//	
//	return userRepository.count(specification);
//}
